/**
 * Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.x2.core.constant.factory;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.x2.base.auth.context.LoginContextHolder;
import com.x2.base.auth.model.LoginUser;
import com.x2.core.cache.CacheTool;
import com.x2.core.constant.cache.CacheKey;
import com.x2.core.constant.state.ManagerStatus;
import com.x2.core.constant.state.MenuStatus;
import com.x2.core.util.SpringContextHolder;
import com.x2.core.util.ToolUtil;
import com.x2.modular.system.entity.*;
import com.x2.modular.system.model.params.DictParam;
import com.x2.modular.system.model.params.DictTypeParam;
import com.x2.modular.system.model.result.DictResult;
import com.x2.modular.system.model.result.DictTypeResult;
import com.x2.modular.system.service.*;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 快捷查询方法
 *
 * @author x2
 * @date 2017年2月13日 下午10:55:21
 */
@Component
@DependsOn("springContextHolder")
public class ConstantFactory {
    private final RoleService roleMapper = SpringContextHolder.getBean(RoleService.class);
    private final DeptService deptMapper = SpringContextHolder.getBean(DeptService.class);
    private final UserService userMapper = SpringContextHolder.getBean(UserService.class);
    private final MenuService menuMapper = SpringContextHolder.getBean(MenuService.class);
    private final NoticeService noticeMapper = SpringContextHolder.getBean(NoticeService.class);
    private final UserRoleService userRoleService = SpringContextHolder.getBean(UserRoleService.class);
    private final DictTypeService dictTypeService = SpringContextHolder.getBean(DictTypeService.class);
    private final DictService dictService = SpringContextHolder.getBean(DictService.class);

    public static ConstantFactory me() {
        return SpringContextHolder.getBean("constantFactory");
    }


    public User getUserById(Long userId) {
        String key = CacheKey.USER_INFO + userId;
        User user = (User) CacheTool.getInstance().get(key);
        if (user == null) {
            user = userMapper.getById(userId);
            if (user != null) {
                CacheTool.getInstance().set(key, user);
            }
        }
        return user;
    }


    public void removeUserById(Long userId) {
        if (userId != null) {
            String key = CacheKey.USER_INFO + userId;
            CacheTool.getInstance().del(key);
        }
    }


    public String getUserNameById(Long userId) {
        if (userId == null) {
            return "";
        }
        String key = CacheKey.USER_NAME + userId;
        String name = (String) CacheTool.getInstance().get(key);
        if (name == null) {
            User user = userMapper.getById(userId);
            if (user != null) {
                name = user.getName();
                CacheTool.getInstance().set(key, name);
            } else {
                name = "--";
            }
        }
        return name;
    }


    public void removeUserNameById(Long userId) {
        if (userId != null) {
            String key = CacheKey.USER_NAME + userId;
            CacheTool.getInstance().del(key);
        }
    }


    public String getUserAccountById(Long userId) {
        String key = CacheKey.USER_ACCOUNT + userId;
        String account = (String) CacheTool.getInstance().get(key);
        if (account == null) {
            User user = userMapper.getById(userId);
            if (user != null) {
                account = user.getAccount();
                CacheTool.getInstance().set(key, account);
            } else {
                account = "--";
            }
        }
        return account;
    }


    public void removeUserAccountById(Long userId) {
        if (userId != null) {
            String key = CacheKey.USER_ACCOUNT + userId;
            CacheTool.getInstance().del(key);
        }
    }


    public String getRoleName(String roleIds) {
        if (ToolUtil.isEmpty(roleIds)) {
            return "";
        }
        String key = CacheKey.ROLES_NAME + roleIds;
        String roleName = (String) CacheTool.getInstance().get(key);
        if (roleName == null) {
            Long[] roles = Convert.toLongArray(roleIds);
            StringBuilder sb = new StringBuilder();
            for (Long role : roles) {
                Role roleObj = roleMapper.getById(role);
                if (ToolUtil.isNotEmpty(roleObj) && ToolUtil.isNotEmpty(roleObj.getName())) {
                    sb.append(roleObj.getName()).append(",");
                }
            }
            roleName = StrUtil.removeSuffix(sb.toString(), ",");
            CacheTool.getInstance().set(key, roleName);
        }
        return roleName;
    }


    public String getRoleNameEx(List<Long> roleIdList) {
        StringBuilder roleIdBuffer = new StringBuilder();
        if (roleIdList == null || roleIdList.size() == 0) {
            return "";
        }
        for (Long a : roleIdList) {
            roleIdBuffer.append(a).append(",");
        }
        String key = CacheKey.ROLES_NAME_LIST + StrUtil.removeSuffix(roleIdBuffer.toString(), ",");
        String roleName = (String) CacheTool.getInstance().get(key);
        if (roleName == null) {
            StringBuilder sb = new StringBuilder();
            for (Long role : roleIdList) {
                Role roleObj = roleMapper.getById(role);
                if (ToolUtil.isNotEmpty(roleObj) && ToolUtil.isNotEmpty(roleObj.getName())) {
                    sb.append(roleObj.getName()).append(",");
                }
            }
            roleName = StrUtil.removeSuffix(sb.toString(), ",");
            CacheTool.getInstance().set(key, roleName);
        }
        return roleName;
    }


    public String getRoleNameByUserId(Long userId) {
        if (userId == null) {
            return "";
        }
        String key = CacheKey.ROLES_NAME_BY_USER_ID + userId;
        String roleName = (String) CacheTool.getInstance().get(key);
        if (roleName == null) {
            List<Long> roleList = this.userRoleService.getRoleList(userId);
            StringBuilder sb = new StringBuilder();
            for (Long role : roleList) {
                Role roleObj = roleMapper.getById(role);
                if (ToolUtil.isNotEmpty(roleObj) && ToolUtil.isNotEmpty(roleObj.getName())) {
                    sb.append(roleObj.getName()).append(",");
                }
            }
            roleName = StrUtil.removeSuffix(sb.toString(), ",");
            CacheTool.getInstance().set(key, roleName);
        }
        return roleName;
    }


    public String getSingleRoleName(Long roleId) {
        if (0 == roleId) {
            return "--";
        }
        String key = CacheKey.SINGLE_ROLE_NAME + roleId;
        String roleName = (String) CacheTool.getInstance().get(key);
        if (roleName == null) {
            Role roleObj = roleMapper.getById(roleId);
            if (ToolUtil.isNotEmpty(roleObj) && ToolUtil.isNotEmpty(roleObj.getName())) {
                roleName = roleObj.getName();
                CacheTool.getInstance().set(key, roleName);
            } else {
                roleName = "";
            }
        }
        return roleName;
    }


    public String getSingleRoleTip(Long roleId) {
        if (0 == roleId) {
            return "--";
        }
        String key = CacheKey.SINGLE_ROLE_TIP + roleId;
        String name = (String) CacheTool.getInstance().get(key);
        if (name == null) {
            Role roleObj = roleMapper.getById(roleId);
            if (ToolUtil.isNotEmpty(roleObj) && ToolUtil.isNotEmpty(roleObj.getName())) {
                name = roleObj.getDescription();
                CacheTool.getInstance().set(key, name);
            } else {
                name = "";
            }
        }
        return name;
    }


    public Dept getDeptById(Long deptId) {
        if (deptId == null) {
            return null;
        }
        String key = CacheKey.DEPT_OBJECT + deptId;
        Dept dept = (Dept) CacheTool.getInstance().get(key);
        if (dept == null) {
            dept = deptMapper.getById(deptId);
            if (dept != null) {
                CacheTool.getInstance().set(key, dept);
            }
        }
        return dept;
    }


    public void removeDeptById(Long deptId) {
        CacheTool.getInstance().del(CacheKey.DEPT_OBJECT + deptId);
    }


    public String getDeptName(Long deptId) {
        if (deptId == null) {
            return "";
        } else if (deptId.compareTo(0L) == 0) {
            return "顶级";
        } else {
            String key = CacheKey.DEPT_NAME + deptId;
            String value = (String) CacheTool.getInstance().get(key);
            if (value == null) {
                Dept dept = deptMapper.getById(deptId);
                if (ToolUtil.isNotEmpty(dept) && ToolUtil.isNotEmpty(dept.getFullName())) {
                    value = dept.getFullName();
                    CacheTool.getInstance().set(key, value);
                } else {
                    value = "";
                }
            }
            return value;
        }
    }


    public Long getDeptIdByName(String deptName) {
        if (StrUtil.isEmpty(deptName)) {
            return -1L;
        } else {
            String key = CacheKey.DEPT_ID + deptName;
            Long value = (Long) CacheTool.getInstance().get(key);
            if (value == null) {
                QueryWrapper<Dept> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("full_name", deptName);
                queryWrapper.select("dept_id deptId");
                Dept dept = deptMapper.getOne(queryWrapper);
                if (ToolUtil.isNotEmpty(dept) && ToolUtil.isNotEmpty(dept.getDeptId())) {
                    value = dept.getDeptId();
                    CacheTool.getInstance().set(key, value);
                } else {
                    value = -1L;
                }
            }
            return value;
        }
    }


    public void removeDeptIdCache(String deptName) {
        if (!ToolUtil.isEmpty(deptName)) {
            CacheTool.getInstance().del(CacheKey.DEPT_ID + deptName);
        }
    }


    public String getMenuNames(String menuIds) {
        Long[] menus = Convert.toLongArray(menuIds);
        StringBuilder sb = new StringBuilder();
        for (Long menu : menus) {
            Menu menuObj = menuMapper.getById(menu);
            if (ToolUtil.isNotEmpty(menuObj) && ToolUtil.isNotEmpty(menuObj.getName())) {
                sb.append(menuObj.getName()).append(",");
            }
        }
        return StrUtil.removeSuffix(sb.toString(), ",");
    }


    public String getMenuName(Long menuId) {
        if (ToolUtil.isEmpty(menuId)) {
            return "";
        } else {
            Menu menu = menuMapper.getById(menuId);
            if (menu == null) {
                return "";
            } else {
                return menu.getName();
            }
        }
    }


    public Menu getMenuByCode(String code) {
        if (ToolUtil.isEmpty(code)) {
            return new Menu();
        } else if (code.equals("0")) {
            return new Menu();
        } else {
            Menu param = new Menu();
            param.setCode(code);
            QueryWrapper<Menu> queryWrapper = new QueryWrapper<>(param);
            Menu menu = menuMapper.getOne(queryWrapper);
            if (menu == null) {
                return new Menu();
            } else {
                return menu;
            }
        }
    }


    public String getMenuNameByCode(String code) {
        if (ToolUtil.isEmpty(code)) {
            return "";
        } else if (code.equals("0")) {
            return "顶级";
        } else {
            Menu param = new Menu();
            param.setCode(code);
            QueryWrapper<Menu> queryWrapper = new QueryWrapper<>(param);
            Menu menu = menuMapper.getOne(queryWrapper);
            if (menu == null) {
                return "";
            } else {
                return menu.getName();
            }
        }
    }


    public Long getMenuIdByCode(String code) {
        if (ToolUtil.isEmpty(code)) {
            return 0L;
        } else if (code.equals("0")) {
            return 0L;
        } else {
            Menu menu = new Menu();
            menu.setCode(code);
            QueryWrapper<Menu> queryWrapper = new QueryWrapper<>(menu);
            Menu tempMenu = this.menuMapper.getOne(queryWrapper);
            return tempMenu.getMenuId();
        }
    }


    public String getNoticeTitle(Long noticeId) {
        if (ToolUtil.isEmpty(noticeId)) {
            return "";
        } else {
            Notice notice = noticeMapper.getById(noticeId);
            if (notice == null) {
                return "";
            } else {
                return notice.getTitle();
            }
        }
    }


    public String getStatusName(String status) {
        return ManagerStatus.getDescription(status);
    }


    public String getMenuStatusName(String status) {
        return MenuStatus.getDescription(status);
    }


    public List<Long> getSubDeptId(Long deptId) {
        ArrayList<Long> deptIds = new ArrayList<>();
        if (deptId == null) {
            return deptIds;
        } else {
            LoginUser user = LoginContextHolder.getContext().getUser();
            if (user == null) {
                return new ArrayList<>();
            }
            List<Dept> depts = this.deptMapper.likePids(deptId);
            if (depts != null && depts.size() > 0) {
                for (Dept dept : depts) {
                    deptIds.add(dept.getDeptId());
                }
            }
            return deptIds;
        }
    }


    public List<Long> getParentDeptIds(Long deptId) {
        Dept dept = deptMapper.getById(deptId);
        String pids = dept.getPids();
        String[] split = pids.split(",");
        ArrayList<Long> parentDeptIds = new ArrayList<>();
        for (String s : split) {
            parentDeptIds.add(Long.valueOf(StrUtil.removeSuffix(StrUtil.removePrefix(s, "["), "]")));
        }
        return parentDeptIds;
    }

    /**
     * 根据字典类型编码获取字典类型对象
     *
     * @param code: 字典类型编码
     * @return 字典类型
     */
    public DictTypeResult getDictTypeByCode(String code) {
        String key = CacheKey.DICT_TYPE + code;
        DictTypeResult value = (DictTypeResult) CacheTool.getInstance().get(key);
        if (value == null) {
            DictTypeParam entity = new DictTypeParam();
            entity.setCode(code);
            value = dictTypeService.findBySpec(entity);
            if (value != null) {
                CacheTool.getInstance().set(key, value);
            }
        }
        return value;
    }


    /**
     * 根据字典类型编码获取字典列表
     *
     * @param pCode: 字典类型编码
     * @return 字典列表
     */

    public List<Map<String, Object>> getDictListByPCode(String pCode) {
        String key = CacheKey.DIC_LIST_BY_PCODE + pCode;
        List<Map<String, Object>> resultList = (List<Map<String, Object>>) CacheTool.getInstance().get(key);
        if (resultList == null) {
            DictTypeResult dictType = getDictTypeByCode(pCode);
            if (dictType == null) {
                return null;
            } else {
                DictParam param = new DictParam();
                param.setDictTypeId(dictType.getDictTypeId());
                param.setOrderColumnCondition("t.sort asc");
                List<DictResult> dicts = this.dictService.findListBySpec(param);
                if (dicts.size() > 0) {
                    resultList = new ArrayList<>();
                    for (DictResult item : dicts) {
                        resultList.add(BeanUtil.beanToMap(item));
                    }
                    CacheTool.getInstance().set(key, resultList);
                    return resultList;
                }
                return null;
            }
        }
        return resultList;
    }

    /**
     * 获取字典名称
     *
     * @param pCode: 字典类型编码
     * @param code:  字典编码
     * @return 字典名称
     */
    public String getDictNameByPCode(String pCode, String code) {
        if (ToolUtil.isEmpty(pCode) || ToolUtil.isEmpty(code)) {
            return "";
        }
        String key = CacheKey.DIC_NAME + pCode + "_" + code;
        String value = (String) CacheTool.getInstance().get(key);
        if (value == null) {
            DictTypeResult dictType = getDictTypeByCode(pCode);
            if (dictType == null) {
                return "";
            }
            DictParam dict = new DictParam();
            dict.setDictTypeId(dictType.getDictTypeId());
            dict.setCode(code);
            DictResult result = dictService.findBySpec(dict);
            if (result != null) {
                value = result.getName();
                CacheTool.getInstance().set(key, value);
            }
        }
        value = value == null ? "" : value;
        return value;
    }


    /**
     * 刷新字典值
     *
     * @param pCode:    字典类型编码
     * @param code：字典编码
     * @param name：新值
     * @return 结果
     */
    public String refreshDictNameByPCode(String pCode, String code, String name) {
        if (!ToolUtil.isEmpty(name)) {
            CacheTool.getInstance().set(CacheKey.DIC_NAME + pCode + "_" + code, name);
        }
        return name;
    }

    /**
     * 刷新字典值
     *
     * @param pCode：字典类型编码
     * @param code:        字典编码
     * @param name：字典值
     * @return 结果
     */
    public String refreshDictCodesByPCode(String pCode, String code, String name) {
        String key = CacheKey.DIC_CODE + pCode + "_" + name;
        if (ToolUtil.isEmpty(name)) {
            CacheTool.getInstance().del(key);
        } else {
            CacheTool.getInstance().set(key, name);
        }
        return code;
    }


    /**
     * 移除缓存
     *
     * @param pCode：父编码
     */
    public void deleteDictListByPCode(String pCode) {
        CacheTool.getInstance().del(CacheKey.DIC_LIST_BY_PCODE + pCode);
    }

    /**
     * 移除字典名缓存
     *
     * @param pCode: 字典类型编码
     * @param code:  字典编码
     */
    public void deleteDictListByPCode(String pCode, String code) {
        CacheTool.getInstance().del(CacheKey.DIC_NAME + pCode + "_" + code);
    }

    /**
     * 删除字典缓存
     *
     * @param pCode:    字典类型编码
     * @param code：字典编码
     * @param name：字典值
     */
    public void deleteDictsByPCode(String pCode, String code, String name) {
        String key1 = CacheKey.DIC_NAME + pCode + "_" + code;
        String key2 = CacheKey.DIC_CODE + pCode + "_" + name;
        String key3 = CacheKey.DIC_LIST_BY_PCODE + pCode;
        CacheTool.getInstance().del(new String[]{key1, key2, key3});
    }
}
